package net.lab1024.sa.admin.common;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.lab1024.sa.admin.config.UserContextHolder;
import net.lab1024.sa.admin.module.business.category.domain.entity.OperationLog;
import net.lab1024.sa.admin.module.business.category.domain.entity.UserContext;
import net.lab1024.sa.admin.module.business.category.service.OperationLogService;
import net.lab1024.sa.base.common.domain.RequestUser;
import net.lab1024.sa.base.common.util.SmartBeanUtil;
import net.lab1024.sa.base.common.util.SmartRequestUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

// 假设的自定义类

@Aspect
@Component
@Slf4j
@RequiredArgsConstructor
public class LogAspect {
    private final OperationLogService logService;
    //private final AddressUtils addressUtils;  // 注入 AddressUtils

    /**
     * 配置切入点：所有标记@Log注解的方法
     */
    @Pointcut("@annotation(net.lab1024.sa.admin.common.Log)")
    public void logPointCut() {
    }

    /**
     * 环绕通知：记录操作日志
     */
    @Around("logPointCut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        // 获取方法签名
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();

        // 获取注解
        Log logAnnotation = method.getAnnotation(Log.class);

        // 创建日志对象

        OperationLog operationLog = new OperationLog();
        operationLog.setModule(logAnnotation.module());
        operationLog.setOperation(logAnnotation.operation());
        operationLog.setMethod(joinPoint.getTarget().getClass().getName() + "." + method.getName());

        // 获取请求参数
        if (logAnnotation.saveParams()) {
            operationLog.setParams(getParams(joinPoint.getArgs()));
        }

        // 获取用户信息（需要实现用户上下文）
        UserContext userContext = UserContextHolder.getUserContext();
        // RequestUser requestUser = SmartRequestUtil.getRequestUser();
        // Long loginUserId = requestUser.getLoginUserId();
        if (userContext != null) {
            operationLog.setOperatorName(userContext.getUsername());
            operationLog.setOperatorCode(userContext.getUserCode());
            operationLog.setOperatorPhone(userContext.getPhone());
        }

        // 获取IP和地理位置
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        operationLog.setIp(IpUtils.getIpAddr(request));
//        operationLog.setLocation(addressUtils.getRealAddressByIP(operationLog.getIp()));
        operationLog.setLocation( "");

        // 记录开始时间
        long startTime = System.currentTimeMillis();

        try {
            // 执行目标方法
            Object result = joinPoint.proceed();

            // 记录执行时间
            long endTime = System.currentTimeMillis();
            operationLog.setExecuteTime(endTime - startTime);

            // 记录成功结果
            operationLog.setResult("成功");

            // 保存响应结果（如果需要）
            if (logAnnotation.saveResult()) {
                operationLog.setResultData(JsonUtils.toJson(result));
            }

            // 异步保存日志
            logService.saveLogAsync(operationLog);

            return result;
        } catch (Exception e) {
            // 记录执行时间
            long endTime = System.currentTimeMillis();
            operationLog.setExecuteTime(endTime - startTime);

            // 记录失败结果
            operationLog.setResult("失败");
            operationLog.setErrorMsg(e.getMessage());

            // 异步保存日志
            logService.saveLogAsync(operationLog);

            throw e;
        }
    }

    /**
     * 获取请求参数
     */
    private String getParams(Object[] paramsArray) {
        try {
            if (paramsArray == null || paramsArray.length == 0) {
                return "";
            }

            // 过滤敏感字段
            List<Object> filteredParams = Arrays.stream(paramsArray)
                    .map(this::filterSensitiveFields)
                    .collect(Collectors.toList());

            return JsonUtils.toJson(filteredParams);
        } catch (Exception e) {
            return "";
        }
    }

    /**
     * 过滤敏感字段
     */
    private Object filterSensitiveFields(Object param) {
        if (param == null) {
            return null;
        }

        // 如果是Map类型
        if (param instanceof Map) {
            Map<String, Object> map = new HashMap<>((Map) param);
            map.keySet().stream()
                    .filter(key -> key.toLowerCase().contains("password") ||
                            key.toLowerCase().contains("token"))
                    .forEach(key -> map.put(key, "******"));
            return map;
        }

        // 如果是对象
        try {
            BeanInfo beanInfo = Introspector.getBeanInfo(param.getClass());
            for (PropertyDescriptor pd : beanInfo.getPropertyDescriptors()) {
                String name = pd.getName();
                if ("password".equalsIgnoreCase(name) ||
                        "token".equalsIgnoreCase(name) ||
                        "secret".equalsIgnoreCase(name)) {
                    Method setter = pd.getWriteMethod();
                    if (setter != null) {
                        setter.invoke(param, "******");
                    }
                }
            }
        } catch (Exception ignored) {
            // 忽略异常
        }

        return param;
    }
}